package controller

import (
	"mini_wms/app/model"

	"github.com/labstack/gommon/log"

	"gorm.io/gorm"

	"mini_wms/app/request"

	"strconv"

	"time"

	"github.com/tealeg/xlsx"
)

type PartManagement struct {
	Base
}

func NewPartManagement() *PartManagement {
	return &PartManagement{}
}

func (c *PartManagement) GetPartList(partCodeReq string) Res {
	log.Info("GetPartList PartManagement")
	log.Info("queryParam: " + partCodeReq)
	var list []model.PartManagement
	if partCodeReq == "" {
		log.Info("GetPartList partCodeReq is null")
		if err := c.db().Where("del_flag = 0").Order("create_time DESC").Find(&list).Error; err != nil {
			c.log(err.Error())
			return c.error("未查询到零件数据")
		}
	} else {
		partCode := "%" + partCodeReq + "%"
		log.Info("GetPartList partCodeReq is " + partCode)
		if err := c.db().Where("del_flag = 0 and part_code LIKE?",partCode).Order("create_time DESC").Find(&list).Error; err != nil {
			c.log(err.Error())
			return c.error("未查询到零件数据")
		}
	}

	return c.success(list)
}

func (c *PartManagement) GetPartById(id string) Res {
	log.Info("GetById PartManagement: " + id)
	var list []model.PartManagement
	if err := c.db().Find(&list).Error; err != nil {
		c.log(err.Error())
		return c.error("未查询到零件数据")
	}

	return c.success(list)
}

func (c *PartManagement) AddPart(partReq request.PartManagementReq) Res {
	log.Info("Add PartManagement")
	var part model.PartManagement = PartReqToPart(partReq)
	part.CreateBy = "Admin"
	part.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	partInput := PartToPartInput(part)
	partInput.CreateBy = "Admin"
	partInput.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	partInput.InputType = 0
	err := c.db().Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&part).Error; err != nil {
			c.log(err.Error())
			return err
		}
		if err := tx.Create(&partInput).Error; err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		c.log(err.Error())
		return c.error("添加零件失败")
	}
	return c.success(nil)
}

func (c *PartManagement) EditPart(partReq request.PartManagementReq) Res {
	log.Info("Edit PartManagement")
	var part model.PartManagement = PartReqToPart(partReq)
	part.UpdateBy = "Admin"
	part.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	var partOld model.PartManagement
	if err := c.db().First(&partOld, part.ID).Error; err != nil {
		c.log(err.Error())
		return c.error("未查询到零件数据")
	}

	err := c.db().Transaction(func(tx *gorm.DB) error {
		if err := tx.Save(&part).Error; err != nil {
			return err
		}
		if partOld.Inventory != part.Inventory {
			partInput := PartToPartInput(part)
			partInput.CreateBy = "Admin"
			partInput.CreateTime = time.Now().Format("2006-01-02 15:04:05")
			partInput.InputType = 3
			if err := tx.Create(&partInput).Error; err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		c.log(err.Error())
		return c.error("更新失败")
	}
	return c.success(nil)
}

func (c *PartManagement) DeletePart(partManagement model.PartManagement) Res {
	log.Info("Delete PartManagement")
	log.Info(partManagement.ID)
	if err := c.db().Model(&partManagement).Update("del_flag", 1).Error; err != nil {
		c.log(err.Error())
		return c.error("删除失败")
	}
	return c.success(nil)
}

func (c *PartManagement) DeleteBatchPart(ids []string) Res {
	log.Info("DeleteBatch PartManagement")
	log.Info(ids)
	return c.success(nil)
}

func (c *PartManagement) ExportPartInput() Res {
	log.Info("Export PartInput")
	var list []model.PartInput
	if err := c.db().Find(&list).Error; err != nil {
		c.log(err.Error())
		return c.error("未查询到零件出入库数据")
	}
	file := xlsx.NewFile()
	sheet, err := file.AddSheet("零件出入库")
	if err != nil {
		log.Error("PartManagement ExportPartInput Error:", err)
		return c.error(err.Error())
	}
	rowTitle := sheet.AddRow()
	cellPartCode := rowTitle.AddCell()
	cellPartCode.Value = "货号"
	cellSkuName := rowTitle.AddCell()
	cellSkuName.Value = "SKU品名"
	cellInputType := rowTitle.AddCell()
	cellInputType.Value = "出入库类型"
	cellInventoryQuantity := rowTitle.AddCell()
	cellInventoryQuantity.Value = "出入库数量"
	cellRemark := rowTitle.AddCell()
	cellRemark.Value = "备注"
	cellCreateBy := rowTitle.AddCell()
	cellCreateBy.Value = "创建人"
	cellCreateTime := rowTitle.AddCell()
	cellCreateTime.Value = "创建日期"

	for _, partInput := range list {
		row := sheet.AddRow()
		cellPartCode := row.AddCell()
		cellPartCode.Value = partInput.PartCode
		cellSkuName := row.AddCell()
		cellSkuName.Value = partInput.SkuName
		cellInputType := row.AddCell()
		if partInput.InputType == 0 {
			cellInputType.Value = "初始化"
		} else if partInput.InputType == 1 {
			cellInputType.Value = "入库"
		} else if partInput.InputType == 2 {
			cellInputType.Value = "出库"
		}else if partInput.InputType == 3 {
			cellInputType.Value = "盘点校正"
		}
		cellInventoryQuantity := row.AddCell()
		cellInventoryQuantity.Value = strconv.Itoa(partInput.InventoryQuantity)
		cellRemark := row.AddCell()
		cellRemark.Value = partInput.Remark
		cellCreateBy := row.AddCell()
		cellCreateBy.Value = partInput.CreateBy
		cellCreateTime := row.AddCell()
		cellCreateTime.Value = partInput.CreateTime
	}
	appPath := c.pathExist(c.getAppPath() + "/outputFile")
	log.Info("appPath: ", appPath)
	file.Save(appPath + "/零件出入库报表.xlsx")
	return c.success(nil)
}

func (c *PartManagement) ExportPart() Res {
	log.Info("Export PartManagement")
	var list []model.PartManagement
	if err := c.db().Where("del_flag = 0").Find(&list).Error; err != nil {
		c.log(err.Error())
		return c.error("未查询到零件数据")
	}
	file := xlsx.NewFile()
	sheet, err := file.AddSheet("零件")
	if err != nil {
		log.Error("PartManagement Export Error:", err)
		return c.error(err.Error())
	}
	rowTitle := sheet.AddRow()
	cellPartCode := rowTitle.AddCell()
	cellPartCode.Value = "货号"
	cellSkuName := rowTitle.AddCell()
	cellSkuName.Value = "SKU品名"
	cellPartLocation := rowTitle.AddCell()
	cellPartLocation.Value = "库存位置"
	cellFirstCategorize := rowTitle.AddCell()
	cellFirstCategorize.Value = "一级分类"
	cellSecondCategorize := rowTitle.AddCell()
	cellSecondCategorize.Value = "二级分类"
	cellPartSize := rowTitle.AddCell()
	cellPartSize.Value = "零件尺寸"
	cellPartColor := rowTitle.AddCell()
	cellPartColor.Value = "零件颜色"
	cellInventory := rowTitle.AddCell()
	cellInventory.Value = "当前余量"
	cellInventoryRequire := rowTitle.AddCell()
	cellInventoryRequire.Value = "库存要求"
	cellRemark := rowTitle.AddCell()
	cellRemark.Value = "备注"
	cellCreateTime := rowTitle.AddCell()
	cellCreateTime.Value = "创建日期"
	cellUpdateTime := rowTitle.AddCell()
	cellUpdateTime.Value = "更新日期"

	for _, part := range list {
		row := sheet.AddRow()
		cellPartCode := row.AddCell()
		cellPartCode.Value = part.PartCode
		cellSkuName := row.AddCell()
		cellSkuName.Value = part.SkuName
		cellPartLocation := row.AddCell()
		cellPartLocation.Value = part.PartLocation
		cellFirstCategorize := rowTitle.AddCell()
		cellFirstCategorize.Value = part.FirstCategorize
		cellSecondCategorize := row.AddCell()
		cellSecondCategorize.Value = part.SecondCategorize
		cellPartSize := row.AddCell()
		cellPartSize.Value = part.PartSize
		cellPartColor := row.AddCell()
		cellPartColor.Value = part.PartColor
		cellInventory := row.AddCell()
		cellInventory.Value = strconv.Itoa(part.Inventory)
		cellInventoryRequire := row.AddCell()
		cellInventoryRequire.Value = part.InventoryRequire
		cellRemark := row.AddCell()
		cellRemark.Value = part.Remark
		cellCreateTime := rowTitle.AddCell()
		cellCreateTime.Value = part.CreateTime
		cellUpdateTime := rowTitle.AddCell()
		cellUpdateTime.Value = part.UpdateTime
	}
	appPath := c.pathExist(c.getAppPath() + "/outputFile")
	log.Info("appPath: ", appPath)
	file.Save(appPath + "/零件管理报表.xlsx")
	return c.success(nil)
}

func (c *PartManagement) ImportPart(filePath string) Res {
	log.Info("Import PartManagement info: " + filePath)
	var list []model.PartManagement
	if err := c.db().Where("del_flag = 0").Find(&list).Error; err != nil {
	}
	partMap := map[string]string{}
	for _, part := range list {
		partMap[part.PartCode] = part.SkuName
	}

	xlFile, err := xlsx.OpenFile(filePath)
	if err != nil {
		return c.error(err.Error())
	}
	partSheet := xlFile.Sheets[0]
	if partSheet == nil {
		return c.error("未找到零件导入文件")
	}
	rowTitle := partSheet.Rows[0]
	if rowTitle == nil || rowTitle.Cells[0].Value != "货号" {
		return c.error("未找到零件导入文件")
	}
	var partExcelList []model.PartManagement
	var partInputList []model.PartInput
	for _, row := range partSheet.Rows[1:] {
		var part model.PartManagement
		if row.Cells[0].Value == "" {
			continue
		}
		if _, ok := partMap[row.Cells[0].Value]; ok {
			continue
		}
		for i := 0; i < len(row.Cells); i++ {
			switch i {
			case 0:
				part.PartCode = row.Cells[i].Value
			case 1:
				part.SkuName = row.Cells[i].Value
			case 2:
				part.PartLocation = row.Cells[i].Value
			case 3:
				part.FirstCategorize = row.Cells[i].Value
			case 4:
				part.SecondCategorize = row.Cells[i].Value
			case 5:
				part.PartSize = row.Cells[i].Value
			case 6:
				part.PartColor = row.Cells[i].Value
			case 7:
				if row.Cells[i].Value == "" {
					part.Inventory = 0
				} else {
					part.Inventory, _ = strconv.Atoi(row.Cells[i].Value)
				}
			case 8:
				part.InventoryRequire = row.Cells[i].Value
			case 9:
				part.Remark = row.Cells[i].Value
			}
		}
		part.CreateBy = "Admin"
		part.CreateTime = time.Now().Format("2006-01-02 15:04:05")
		partExcelList = append(partExcelList, part)

		partInput := PartToPartInput(part)
		partInput.CreateBy = "Admin"
		partInput.CreateTime = time.Now().Format("2006-01-02 15:04:05")
		partInput.InputType = 0
		partInputList = append(partInputList, partInput)
	}
	errorT := c.db().Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&partInputList).Error; err != nil {
			c.log(err.Error())
			return err
		}
		if err := tx.Create(&partExcelList).Error; err != nil {
			c.log(err.Error())
			return err
		}
		return nil
	})
	if errorT != nil {
		c.log(errorT.Error())
		return c.error("导入失败")
	}
	return c.success(nil)
}

func (c *PartManagement) DownloadPartTemplate() error {
	log.Info("DownloadTemplate PartManagement")
	file := xlsx.NewFile()
	sheet, err := file.AddSheet("零件导入模板")
	if err != nil {
		log.Error("PartManagement DownloadPartTemplate Error:", err)
		return err
	}
	rowTitle := sheet.AddRow()
	cellPartCode := rowTitle.AddCell()
	cellPartCode.Value = "货号"
	cellSkuName := rowTitle.AddCell()
	cellSkuName.Value = "SKU品名"
	cellPartLocation := rowTitle.AddCell()
	cellPartLocation.Value = "库存位置"
	cellFirstCategorize := rowTitle.AddCell()
	cellFirstCategorize.Value = "一级分类"
	cellSecondCategorize := rowTitle.AddCell()
	cellSecondCategorize.Value = "二级分类"
	cellPartSize := rowTitle.AddCell()
	cellPartSize.Value = "零件尺寸"
	cellPartColor := rowTitle.AddCell()
	cellPartColor.Value = "零件颜色"
	cellInventory := rowTitle.AddCell()
	cellInventory.Value = "当前余量"
	cellInventoryRequire := rowTitle.AddCell()
	cellInventoryRequire.Value = "库存要求"
	cellRemark := rowTitle.AddCell()
	cellRemark.Value = "备注"

	appPath := c.pathExist(c.getAppPath() + "/outputFile")
	log.Info("appPath: ", appPath)
	return file.Save(appPath + "/零件导入模板.xlsx")
}

func (c *PartManagement) GetPartInputList(partCodeReq string) Res {
	log.Info("GetPartInputList")
	log.Info("queryParam: " + partCodeReq)
	var list []model.PartInput
	if partCodeReq == "" {
		log.Info("GetPartInputList partCodeReq is null")
		if err := c.db().Order("create_time DESC").Find(&list).Error; err != nil {
			c.log(err.Error())
			return c.error("未查询到零件数据")
		}
	}else{
		partCode := "%" + partCodeReq + "%"
		log.Info("GetPartInputList partCodeReq is " + partCode)
		if err := c.db().Where("part_code LIKE?",partCode).Order("create_time DESC").Find(&list).Error; err != nil {
			c.log(err.Error())
			return c.error("未查询到零件数据")
		}
	}

	return c.success(list)
}

func (c *PartManagement) AddPartInput(partInputReq request.PartInputReq) Res {
	log.Info("Add PartInput")
	log.Info("partInputReq Id: ", partInputReq.ID)
	var part model.PartManagement
	if err := c.db().Where("del_flag = 0 and id = ?", partInputReq.ID).Find(&part).Error; err != nil {
		c.log(err.Error())
		return c.error("未查询到零件数据")
	}
	var partInput model.PartInput = PartInputReqToPartInput(partInputReq)
	partInput.InputType = 1
	partInput.CreateBy = "Admin"
	partInput.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	part.Inventory += partInput.InventoryQuantity
	part.UpdateBy = "Admin"
	part.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	err := c.db().Transaction(func(tx *gorm.DB) error {
		if err := tx.Save(&part).Error; err != nil {
			return err
		}
		if err := tx.Create(&partInput).Error; err != nil {
			c.log(err.Error())
			return err
		}
		return nil
	})

	if err != nil {
		c.log(err.Error())
		return c.error("入库失败")
	}

	return c.success(nil)
}

func PartReqToPart(partReq request.PartManagementReq) model.PartManagement {
	var part model.PartManagement = model.PartManagement{}
	log.Info("partReq.ID:", partReq.ID)
	if partReq.ID != 0 {
		part.ID = partReq.ID
	}
	part.PartCode = partReq.PartCode
	part.SkuName = partReq.SkuName
	part.PartLocation = partReq.PartLocation
	part.SecondCategorize = partReq.SecondCategorize
	part.PartSize = partReq.PartSize
	part.PartColor = partReq.PartColor
	inventory, err := strconv.Atoi(partReq.Inventory)
	if err != nil {
		log.Error("PartReqToPart inventory Error:", err)
	}
	part.Inventory = inventory
	part.InventoryRequire = partReq.InventoryRequire
	part.Remark = partReq.Remark
	part.CreateBy = partReq.CreateBy
	part.CreateTime = partReq.CreateTime
	part.UpdateBy = partReq.UpdateBy
	part.UpdateTime = partReq.UpdateTime
	return part
}

func PartToPartInput(part model.PartManagement) model.PartInput {
	var partInput model.PartInput = model.PartInput{}
	partInput.PartCode = part.PartCode
	partInput.SkuName = part.SkuName
	partInput.InventoryQuantity = part.Inventory
	partInput.Remark = part.Remark
	return partInput
}

func PartInputReqToPartInput(partInputReq request.PartInputReq) model.PartInput {
	var partInputModel model.PartInput = model.PartInput{}
	partInputModel.PartCode = partInputReq.PartCode
	partInputModel.SkuName = partInputReq.SkuName
	inventoryQuantity, err := strconv.Atoi(partInputReq.InventoryQuantity)
	if err != nil {
		log.Error("PartInputReqToPartInput inventoryQuantity Error:", err)
	}
	partInputModel.InventoryQuantity = inventoryQuantity
	partInputModel.Remark = partInputReq.Remark
	return partInputModel
}
